﻿using AF_Application.Interface.Cache;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;

namespace AF_Cache.Session
{
    public class CouchbaseSessionCacheProvider : ISessionCacheProvider
    {
        private static readonly object lockObj = new object();
        private string _SessionDataBucketName;
        private string _SessionDataBucketPassword;
        private uint _DefSessionLifeSeconds = 120;
        private string _AppName;
        private ICacheProvider CacheProvider;
        public bool UseCouchbaseCache = false;

        public string DistributedSessionKey
        {
            get
            {
                _AppName = System.Configuration.ConfigurationManager.AppSettings["AppName"].ToString();
                if (string.IsNullOrEmpty(_AppName))
                {
                    throw new Exception("请在Config文件AppSetting中配置AppName项");
                }
                return Encrypt(_AppName + "_UNID", "zhouning", "afocus15").ToLower().Replace("=", "").Replace("-", "");
            }
        }
        public string DistributedSessionID
        {
            get
            {
                string _DistributedSessionID = "";
                if (HttpContext.Current.Request.Cookies[DistributedSessionKey] != null && !string.IsNullOrEmpty(HttpContext.Current.Request.Cookies[DistributedSessionKey].Value))
                {
                    _DistributedSessionID = HttpContext.Current.Request.Cookies[DistributedSessionKey].Value;
                }
                else if (HttpContext.Current.Response.Cookies[DistributedSessionKey] != null && !string.IsNullOrEmpty(HttpContext.Current.Response.Cookies[DistributedSessionKey].Value))
                {
                    _DistributedSessionID = HttpContext.Current.Response.Cookies[DistributedSessionKey].Value;
                }
                else
                {
                    _DistributedSessionID = Guid.NewGuid().ToString().Replace("-", "");
                    if (HttpContext.Current.Response.Cookies[DistributedSessionKey] != null)
                    {
                        HttpContext.Current.Response.Cookies[DistributedSessionKey].Value = _DistributedSessionID;
                    }
                    else
                    {
                        HttpContext.Current.Response.Cookies.Add(new HttpCookie(DistributedSessionKey, _DistributedSessionID));
                    }
                }
                return _DistributedSessionID.Replace("=", "").Replace("-", "");
            }
        }

        public CouchbaseSessionCacheProvider(ICacheProvider cacheProvider)
        {
            CacheProvider = cacheProvider;

            if (System.Configuration.ConfigurationManager.AppSettings.AllKeys.Contains("SessionCacheMode"))
            {
                UseCouchbaseCache = System.Configuration.ConfigurationManager.AppSettings["SessionCacheMode"].ToString().ToLower() == "couchbase";
            }
            _SessionDataBucketName = System.Configuration.ConfigurationManager.AppSettings["SessionDataBucketName"].ToString();
            _SessionDataBucketPassword = System.Configuration.ConfigurationManager.AppSettings["SessionDataBucketPassword"].ToString();

            string strDefSessionLifeSeconds = System.Configuration.ConfigurationManager.AppSettings["DefSessionLifeSeconds"].ToString();
            uint.TryParse(strDefSessionLifeSeconds, out _DefSessionLifeSeconds);
        }

        public bool Set<T>(string key, T data, uint lifeSeconds = 1200)
        {
            bool result = false;
            if (!string.IsNullOrEmpty(key))
            {
                    if (!UseCouchbaseCache)
                    {
                        if (HttpContext.Current == null)
                        {
                            //UnitTest时直接跳过
                            return false;
                        }
                        key = "SessionID_" + DistributedSessionID + "_" + key;
                        CacheEntity<T> Data = new CacheEntity<T>() { DataType = typeof(T).Name, Data = data };
                        string jsonData = Newtonsoft.Json.JsonConvert.SerializeObject(Data);
                        HttpContext.Current.Session[key] = jsonData;
                        result = true;
                    }
                    else
                    {
                        key = "SessionID_" + DistributedSessionID + "_" + key;
                        result = CacheProvider.Set<T>(key.ToLower(), data, lifeSeconds, _SessionDataBucketName, _SessionDataBucketPassword);
                    }
            }
            return result;
        }

        public T Get<T>(string key)
        {
            T result = default(T);
            if (!string.IsNullOrEmpty(key))
            {
                try
                {
                    if (!UseCouchbaseCache)
                    {
                        if (HttpContext.Current == null)
                        {
                            //UnitTest时直接跳过
                            return default(T);
                        }
                        key = "SessionID_" + DistributedSessionID + "_" + key;
                        CacheEntity<T> ResultData = Newtonsoft.Json.JsonConvert.DeserializeObject<CacheEntity<T>>(HttpContext.Current.Session[key].ToString());
                        result = ResultData.Data;
                    }
                    else
                    {
                        key = "SessionID_" + DistributedSessionID + "_" + key;
                        result = CacheProvider.Get<T>(key.ToLower(), _SessionDataBucketName, _SessionDataBucketPassword);
                    }
                }
                catch
                {
                    //ErrorCount++;
                }
            }
            return result;
        }

        public object Get(string key, Type type)
        {
            object result = null;
            if (!string.IsNullOrEmpty(key))
            {
                try
                {
                    if (!UseCouchbaseCache)
                    {
                        if (HttpContext.Current == null)
                        {
                            //UnitTest时直接跳过
                            return false;
                        }
                        key = "SessionID_" + DistributedSessionID + "_" + key;
                        JObject JOBJ = JObject.Parse(HttpContext.Current.Session[key].ToString());
                        string DataJson = JOBJ["Data"].ToString();
                        result = Newtonsoft.Json.JsonConvert.DeserializeObject(DataJson, type);
                    }
                    else
                    {
                        key = "SessionID_" + DistributedSessionID + "_" + key;
                        result = CacheProvider.Get(key.ToLower(), type, _SessionDataBucketName, _SessionDataBucketPassword);
                    }
                }
                catch
                {
                    //ErrorCount++;
                }
            }
            return result;
        }


        public bool Remove(string key)
        {
            bool result = false;
            if (!string.IsNullOrEmpty(key))
            {
                try
                {
                    if (!UseCouchbaseCache)
                    {
                        if (HttpContext.Current == null)
                        {
                            //UnitTest时直接跳过
                            return false;
                        }
                        key = "SessionID_" + DistributedSessionID + "_" + key;
                        HttpContext.Current.Session.Remove(key);
                    }
                    else
                    {
                        key = "SessionID_" + DistributedSessionID + "_" + key;
                        result = CacheProvider.Remove(key.ToLower(), _SessionDataBucketName, _SessionDataBucketPassword);
                    }
                }
                catch
                {
                    //ErrorCount++;
                }
            }
            return result;
        }

        public bool Exists(string key)
        {
            bool result = false;
            if (!string.IsNullOrEmpty(key))
            {
                try
                {
                    if (!UseCouchbaseCache)
                    {
                        if (HttpContext.Current == null)
                        {
                            //UnitTest时直接跳过
                            return false;
                        }
                        key = "SessionID_" + DistributedSessionID + "_" + key;
                        result = HttpContext.Current.Session[key] != null;
                    }
                    else
                    {
                        key = "SessionID_" + DistributedSessionID + "_" + key;
                        result = CacheProvider.Exists(key.ToLower(), _SessionDataBucketName, _SessionDataBucketPassword);
                    }
                }
                catch
                {
                    //ErrorCount++;
                }
            }
            return result;
        }

        private string Encrypt(string sourceString, string key, string iv)
        {
            try
            {
                string result = "";
                byte[] btKey = Encoding.UTF8.GetBytes(key);
                byte[] btIV = Encoding.UTF8.GetBytes(iv);
                DESCryptoServiceProvider des = new DESCryptoServiceProvider();
                using (MemoryStream ms = new MemoryStream())
                {
                    byte[] inData = Encoding.UTF8.GetBytes(sourceString);
                    try
                    {
                        using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(btKey, btIV), CryptoStreamMode.Write))
                        {
                            cs.Write(inData, 0, inData.Length);
                            cs.FlushFinalBlock();
                        }
                        result = Convert.ToBase64String(ms.ToArray());
                    }
                    catch
                    {
                        result = sourceString;
                    }
                }
                return Regex.Replace(result, "[^a-z|A-Z|0-9]", "");
            }
            catch { }
            return "DES加密出错";
        }



        public void Dispose()
        {
        }
    }
}
